초기화 컨테이너

개요

init container.
직관적으로만 봐도 초기화를 진행하는 컨테이너라는 것을 알 수 있다.
이걸 통해 앱 컨테이너가 동작하기 전에 기본적으로 구축해야 할 설정과 동작을 수행할 수 있다.
참고로 여기에서 파생되어 나오는 것 중 하나가 사이드카 컨테이너이다.

특징

개념 자체는 쉬우니 바로 특징으로 넘어가도록 하자.

Pasted image 20240820154805.png
위와 같이 초기화 컨테이너가 실행 중일 때 파드는 Pending상태에 머물러 있다.

다른 컨테이너와의 차이

사용법

초기화 컨테이너는 다음의 세 가지 상황에서 매우 유용하게 사용할 수 있다.

용례

for i in {1..100}; do sleep 1; if nslookup myservice; then exit 0; fi; done; exit 1

다른 서비스가 확실히 만들어지기 전까지 기다리기.
이 예시는 앱 컨테이너에 nslookup이 없어도 돼서 더 좋다.

curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'

Downward API를 사용해 파드의 정보를 앱 실행 전에 등록하고 싶을 때.

sleep 60

그냥 시간 기다리기
이밖에도 깃 주소를 받아서 앱 컨테이너에 볼륨으로 공유하기, 템플릿 툴을 사용해 설정 파일을 앱 컨테이너에 공유하기 등의 작업을 수행할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

위와 같이 until을 사용해서 내가 원하는 서비스가 올라올 때까지 대기를 시키는 방식은 매우 유용하다.

유의 사항

몇 가지 유의할 만한 사항이 있다.
초기화 컨테이너를 사용하는데 있어서 알아두면 둬야 할 상세 동작들이라고 할 수 있겠다.

재시작

restartPolicy에 대해

파드의 파드 속 컨테이너의 장애#재시작 정책(restartPolicy)을 따르지만, Always인 경우에는 OnFailure가 적용된다.
달리 말하자면 기본적으로 OnFailure이지만 파드의 재시작 정책이 Never인 경우에는 Never로 적용된다고 표현할 수도 있을 것 같다.
초기화 컨테이너가 성공적으로 수행되도 재시작된다면, 앱 컨테이너가 영원히 동작할 수 없으니 어쩌면 당연하다.
다른 문서에서 애매하게 적혀 있어서 T-초기화 컨테이너는 재시작되는가하는 고민까지 하게 만들어준 공식 문서에 다시금 감사를 표한다..

앱 컨테이너 정책 초기화 컨테이너 정책
Always OnFailure
OnFailure OnFailure
Never Never
이렇게 정리해볼 수 있을 듯하다.

파드의 재시작

초기화 컨테이너는 파드가 동작하는 시점에서 가장 선행되는 프로세스이다.
파드가 동작하는 시점이란 파드를 위한 네트워크, 스토리지 세팅이 완료된 이후를 말한다.
그래서 파드=초기화 컨테이너 정도의 밀접한 관계를 맺는다고도 말할 수 있다.
달리 말해 파드가 재시작하면 모든 초기화 컨테이너도 다시 실행한다.
이건 당연하게 들린다.

그러나 1.20 버전 이전에는 그 역도 거의 성립하다시피 했다.
현재는 그렇지는 않다고 하는 듯하다.
다음은 파드가 재시작되는 경우.

위 상황들이 궁금해서 조금 T-초기화 컨테이너의 이미지 바꾸기 테스트를 해봤다.
문서와는 조금 다른 구석이 있는 것 같으니 문서 설명을 너무 맹신하지는 말자.
결국 1.20 버전 이후부터는 첫번째 경우 말고는 파드가 재시작되는 경우가 없는 것으로 생각하면 될 듯하다.

리소스 공유

각 파드는 적정한 리소스 값을 가진다.
그리고 그것은 당연히 내부 컨테이너가 가질 수 있는 리소스 값에 달려있다.

이걸 왜 초기화 컨테이너에서 언급하는가?
초기화 컨테이너 중에서 가장 높게 리소스 제한이 걸린 값을 유효 초기 요청/제한이라고 부른다.
초기화 컨테이너 중 리소스 명시가 안 된 컨테이너는 이 값을 기준으로 제한이 걸린다.

이게 중요한 이유는 파드가 받을 수 있는 리소스의 값에 영향을 준다는 것이다.
파드의 리소스 스케줄링은 다음 중 더 높은 값을 토대로 이뤄진다.

무슨 말이냐, 초기화 컨테이너는 파드의 라이프사이클에는 영향을 주지도 않는 주제에 파드의 리소스를 많이 걸어버릴 수도 있다는 것이다.

참고로 초기 컨테이너와 앱 컨테이너의 QoS 계층은 동일하다.

케이스가 많지는 않지만, 초기화 컨테이너 역시 재시작될 가능성은 분명히 존재한다.
가령 모종의 이유로 컨테이너가 실패하게 된다던가 하는 상황이다.
그러니 멱등(idempotent)한 코드를 짜는 것이 중요하다.
EmptyDirs에 이전 초기화 컨테이너가 실행한 결과로 인한 오작동에 대한 대비책은 마련되어 있어야만 한다.

activeDeadlineSeconds를 써서 초기화 컨테이너가 무한 지속되는 상황을 미연에 방지할 수 있다.
그러나 이건 앱 컨테이너에도 적용되니까 한번 실행되고 끝나는 Job에 대해서만 적용하길 추천한다.

초기화 컨테이너끼리의 이름은 고유해야만 한다.

관련 문서

참고